/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package classcreator;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.util.Vector;

/**
 *
 * @author Stefano
 */
public class StateMachine{
    private static double outputFormatVersion=1.1;
    
    
    public String name="";
    public String extended="";
    public Vector<String> interfaced=new Vector<String>();
    public Vector<Field> fields=new Vector<Field>();
    public Vector<Method> methods=new Vector<Method>();
    public boolean blankBuildable=false;
    public boolean defaultBuildable=true;
    
    public Vector<Field> inherited=new Vector<Field>();
    
    public int actualState=0;
    public Vector<State> states=new Vector<State>();
    public Vector<Transition> transitions=new Vector<Transition>();
    
    public Type getType(){
        return new Type(name,Naming.defaultPackageName);
    }
    
    public void addState(String sn){
        states.add(new State(actualState,sn));
        actualState++;
    }
    
    public void removeStateAt(int i){
        if(i>1&& i<states.size()) states.remove(i);
    }
    
    public StateMachine(String n){
        name=n;
        interfaced.add("StateMachine");
        addState("Initial");
        states.add(new State(-1,"Final pseudoState"));
    }
    
    public State getStateFromID(int stateID){
        for(State s:states){
            if(s.id==stateID){
                return s;
            }
        }
        return null;
    }
    
    public boolean addField(Field f){
        for(Field field:fields){
            if(field.name.equals(f.name)) return false;
        }
        fields.add(f);
        return true;
    }
    
    public boolean addInheritedField(Field f){
        for(Field field:inherited){
            if(field.name.equals(f.name)) return false;
        }
        inherited.add(f);
        return true;
    }
    
    public boolean addMethod(Method m){
        for(Method method:methods){
            if(method.header.name.equals(m.header.name)){
                for(int i=0; i<method.header.parameters.size(); i++){
                    if(!m.header.parameters.get(i).type.equals(method.header.parameters.get(i).type)){
                        methods.add(m);
                        return true;
                    }
                }
                return false;
            }
        }
        methods.add(m);
        return true;
    }
    
    public boolean addMethod(Transition m){
        for(Transition method:transitions){
            if(method.header.name.equals(m.header.name)){
                for(int i=0; i<method.header.parameters.size(); i++){
                    if(!m.header.parameters.get(i).type.equals(method.header.parameters.get(i).type)){
                        transitions.add(m);
                        return true;
                    }
                }
                method.addTransitionInfos(m.transinfo);
                return false;
            }
        }
        transitions.add(m);
        return true;
    }

    public String toString(){
        String s="package "+Naming.defaultPackageName+";\n\n";
        s=s+"public class ";
        s=s+name;
        if(!extended.isEmpty()){
            s=s+" extends "+extended;
        }
        if(interfaced.size()>0){
            s=s+" implements ";
        }
        for(String d:interfaced){
            s=s+d+", ";
        }
        if(interfaced.size()>0){
            s=s.substring(0, s.length()-2);
        }
        s=s+" {\n";
        for(Field p:fields){
            s=s+p.toString()+"\n";
        }
        s=s+"\n";
        
        Constructor bc=new Constructor(name,fields);
        bc.body.add(Naming.stateMachineSetState+"(0);");
        if(blankBuildable) s=s+(bc).toString()+"\n";
        Constructor dc=new Constructor(name,fields,inherited);
        dc.body.add(Naming.stateMachineSetState+"(0);");
        if(defaultBuildable) s=s+(dc).toString()+"\n";
        for(Method m:methods){
            s=s+m.toString()+"\n";
        }
        for(Transition m:transitions){
            s=s+m.toString()+"\n";
        }
        s=s+"\n}";
        return s;
    }
    
    public static StateMachine parse(BufferedReader br, TypeRepository tr) throws IOException{
                br.readLine();
                double version=Double.parseDouble(br.readLine());
                
                if(version<=1.0){
                    int n;
                    StateMachine d=new StateMachine(br.readLine());
                    d.extended=br.readLine();
                    n=Integer.parseInt(br.readLine());
                    for(int i=0; i<n; i++){
                        if(i>0)d.interfaced.add(br.readLine());
                        else br.readLine();
                    }
                    n=Integer.parseInt(br.readLine());
                    for(int i=0; i<n; i++){
                        d.fields.add(Field.parse(br, tr));
                    }
                    n=Integer.parseInt(br.readLine());
                    for(int i=0; i<n; i++){
                        d.methods.add(Method.parse(br, tr));
                    }
                    d.blankBuildable=Boolean.parseBoolean(br.readLine());
                    d.defaultBuildable=Boolean.parseBoolean(br.readLine());
                    n=Integer.parseInt(br.readLine());
                    for(int i=0; i<n; i++){
                        if(i>1)d.states.add(State.parse(br, tr));
                        else State.parse(br, tr);
                    }
                    n=Integer.parseInt(br.readLine());
                    for(int i=0; i<n; i++){
                        d.transitions.add(Transition.parse(br, tr));
                    }

                    return d;
                }
                if(outputFormatVersion<=1.1){
                    int n;
                    StateMachine d=new StateMachine(br.readLine());
                    d.extended=br.readLine();
                    n=Integer.parseInt(br.readLine());
                    for(int i=0; i<n; i++){
                        if(i>0)d.interfaced.add(br.readLine());
                        else br.readLine();
                    }
                    n=Integer.parseInt(br.readLine());
                    for(int i=0; i<n; i++){
                        d.fields.add(Field.parse(br, tr));
                    }
                    n=Integer.parseInt(br.readLine());
                    for(int i=0; i<n; i++){
                        d.methods.add(Method.parse(br, tr));
                    }
                    d.blankBuildable=Boolean.parseBoolean(br.readLine());
                    d.defaultBuildable=Boolean.parseBoolean(br.readLine());
                    n=Integer.parseInt(br.readLine());
                    for(int i=0; i<n; i++){
                        if(i>1)d.states.add(State.parse(br, tr));
                        else State.parse(br, tr);
                    }
                    n=Integer.parseInt(br.readLine());
                    for(int i=0; i<n; i++){
                        d.transitions.add(Transition.parse(br, tr));
                    }
                    n=Integer.parseInt(br.readLine());
                    for(int i=0; i<n; i++){
                        d.inherited.add(Field.parse(br, tr));
                    }
                    return d;
                }
                //Actual version
                int n;
                StateMachine d=new StateMachine(br.readLine());
                d.extended=br.readLine();
                n=Integer.parseInt(br.readLine());
                for(int i=0; i<n; i++){
                    if(i>0)d.interfaced.add(br.readLine());
                    else br.readLine();
                }
                n=Integer.parseInt(br.readLine());
                for(int i=0; i<n; i++){
                    d.fields.add(Field.parse(br, tr));
                }
                n=Integer.parseInt(br.readLine());
                for(int i=0; i<n; i++){
                    d.methods.add(Method.parse(br, tr));
                }
                d.blankBuildable=Boolean.parseBoolean(br.readLine());
                d.defaultBuildable=Boolean.parseBoolean(br.readLine());
                n=Integer.parseInt(br.readLine());
                for(int i=0; i<n; i++){
                    if(i>1)d.states.add(State.parse(br, tr));
                    else State.parse(br, tr);
                }
                n=Integer.parseInt(br.readLine());
                for(int i=0; i<n; i++){
                    d.transitions.add(Transition.parse(br, tr));
                }
                n=Integer.parseInt(br.readLine());
                for(int i=0; i<n; i++){
                    d.inherited.add(Field.parse(br, tr));
                }
                return d;
    }
    
    public void permanentize(BufferedWriter br, TypeRepository tr) throws IOException{
        br.write("/***/ State Machine: "+name); br.newLine();
        br.write(String.valueOf(outputFormatVersion)); br.newLine();
        br.write(name); br.newLine();
        br.write(extended); br.newLine();
        br.write(String.valueOf(interfaced.size())); br.newLine();
        for(String s:interfaced){
            br.write(s); br.newLine();
        }
        br.write(String.valueOf(fields.size())); br.newLine();
        for(Field s:fields){
            s.permanentize(br, tr);
        }
        br.write(String.valueOf(methods.size())); br.newLine();
        for(Method s:methods){
            s.permanentize(br, tr);
        }
        br.write(String.valueOf(blankBuildable)); br.newLine();
        br.write(String.valueOf(defaultBuildable)); br.newLine();
        
        br.write(String.valueOf(states.size())); br.newLine();
        for(State s:states){
            s.permanentize(br, tr);
        }
        br.write(String.valueOf(transitions.size())); br.newLine();
        for(Transition s:transitions){
            s.permanentize(br, tr);
        }
        br.write(String.valueOf(inherited.size())); br.newLine();
        for(Field s:inherited){
            s.permanentize(br, tr);
        }
        
    }
}
